package com.rzjm.exercise.common.utils;

import com.rzjm.exercise.common.exception.FileException;
import com.rzjm.exercise.common.exception.ProcessException;
import com.rzjm.exercise.common.exception.UnexpectedException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

/**
 * 操作系统的工具类
 * 
 * @author zhangjr@sunwayworld.com 2018年1月22日
 *
 */
public abstract class SystemUtils {
    private static final Logger logger = LogManager.getLogger(SystemUtils.class);
    
    private static final boolean IS_OS_WINDOWS = StringUtils.startsWith(getSystemProperty("os.name"), "Windows");
    private static final boolean IS_OS_MAC = StringUtils.startsWith(getSystemProperty("os.name"), "Mac");
    
    /**
     * 判断操作系统是否是windows
     * 
     * @return true：操作系统是windows false：其它操作系统
     */
    public static final boolean isWindows() {
        return IS_OS_WINDOWS;
    }
    
    /**
     * 判断操作系统是否是linux
     * 
     * @return true：操作系统是linux false：其它操作系统
     */
    public static final boolean isLinux() {
        return !IS_OS_WINDOWS && !IS_OS_MAC;
    }
    
	/**
     * 获取当前运行应用的根目录（可能和应用所在的目录不一致）
     * 
     * @return 当前运行应用的根目录
     */
    public static final Path getWorkingPath() {
    	return Paths.get(System.getProperty("user.dir"));
    }
    
    /**
     * 执行指定的操作系统的命令并返回其执行结果
     * 
     * @param cmd
     *            要执行的命令
     * @return 执行结果
     */
    public static final String execAndReturn(String cmd) {
        try {
            Process process = Runtime.getRuntime().exec(cmd);
            
            OutputInterceptor error = new OutputInterceptor(process.getErrorStream());
            
            error.start();
            
            String output = getInputStreamContent(process.getInputStream());
            
            process.waitFor();
            
            return output;
        } catch (IOException ioe) {
            throw new FileException(ioe);
        } catch (InterruptedException ie) {
            throw new ProcessException(ie);
        }
    }
    
    /**
     * 执行指定的操作系统的命令
     * 
     * @param cmd
     *            要执行的命令
     */
    public static final void exec(String cmd) {
        try {
            Process process = Runtime.getRuntime().exec(cmd);
            
            OutputInterceptor error = new OutputInterceptor(process.getErrorStream());
            OutputInterceptor output = new OutputInterceptor(process.getInputStream());
            
            error.start();
            output.start();
            
            process.waitFor();
        } catch (IOException ioe) {
            throw new FileException(ioe);
        } catch (InterruptedException ie) {
            throw new ProcessException(ie);
        }
    }
    
    /**
     * 获取当前系统中的mac地址
     */
    public static final List<String> getMacAddresses() {
        try {
            Enumeration<NetworkInterface> niEnum = NetworkInterface.getNetworkInterfaces();
            
            List<String> macAddressList = new ArrayList<>();
            
            while (niEnum.hasMoreElements()) {
                NetworkInterface ni = niEnum.nextElement();
                
                if (ni.isPointToPoint()
                        || ni.isVirtual()) {
                    continue;
                }
                
                byte[] bytes = ni.getHardwareAddress();
                
                if (bytes != null) {
                    // 下面代码是把mac地址拼装成String
                    StringBuilder sb = new StringBuilder();
                    
                    for (int i = 0; i < bytes.length; i++) {
                        if (i != 0) {
                            sb.append("-");
                        }
                        
                        // mac[i] & 0xFF 是为了把byte转化为正整数
                        String s = Integer.toHexString(bytes[i] & 0xFF);
                        sb.append(s.length() == 1 ? 0 + s : s);
                    }
                    
                    macAddressList.add(sb.toString().toUpperCase());
                }
            }
            
            return macAddressList;
        } catch (SocketException se) {
            throw new UnexpectedException(se);
        }
    }
    
    /**
     * 获取操作系统的名称
     */
    public static final String getOSName() {
        return getSystemProperty("os.name");
    }
    
    // --------------------------------------------------------------------
    // 私有方法
    // --------------------------------------------------------------------
    private static class OutputInterceptor extends Thread {
        private InputStream is;
        
        public OutputInterceptor(InputStream is){
            this.is = is;
        }
        
        public void run() {
            String result = getInputStreamContent(is);
            
            if (!StringUtils.isEmpty(result)) {
                logger.info(result);
            }
        }
    }
    
    private static String getInputStreamContent(InputStream is) {
        try (BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
            StringBuilder info = new StringBuilder();
            String line = null;
            while ((line = br.readLine()) != null) {
                if (info.length() > 0) {
                    info.append("\n");
                }
                
                info.append(line);
            }
            
            return info.toString();
        } catch (IOException ioe) {
            return "";
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    /* ignore */
                }
            }
        }
    }
    
    private static final String getSystemProperty(String property) {
        try {
            return System.getProperty(property);
        } catch (SecurityException se) {
            throw new UnexpectedException(se);
        }
    }
    
}
